package city.spring.modules.system.controller;

import city.spring.modules.system.entity.OrganizationEntity;
import city.spring.modules.system.entity.PermissionEntity;
import city.spring.modules.system.entity.RoleEntity;
import city.spring.modules.system.service.OrganizationService;
import city.spring.modules.system.service.PermissionService;
import city.spring.modules.system.service.RoleService;
import city.spring.utils.MyBatisUtils;
import city.spring.utils.OrganizationUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * Controller：组织机构
 *
 * @author 侯坤林
 * @date 2020-05-30 14:06:37
 */
@RestController
@RequestMapping("/organization")
public class OrganizationController extends ApiController {
    private final OrganizationService organizationService;
    private final RoleService roleService;
    private final PermissionService permissionService;
    /**
     * 实体类可排序字段
     */
    private final List<SFunction<OrganizationEntity, ?>> entityOrderFields;

    public OrganizationController(OrganizationService organizationService, RoleService roleService, PermissionService permissionService) {
        this.organizationService = organizationService;
        this.roleService = roleService;
        this.permissionService = permissionService;
        entityOrderFields = new ArrayList<>();
        entityOrderFields.add(OrganizationEntity::getId);
        entityOrderFields.add(OrganizationEntity::getPid);
        entityOrderFields.add(OrganizationEntity::getTitle);
        entityOrderFields.add(OrganizationEntity::getRemarks);
        entityOrderFields.add(OrganizationEntity::getVersion);
        entityOrderFields.add(OrganizationEntity::getGmtCreate);
        entityOrderFields.add(OrganizationEntity::getGmtModified);
    }

    /**
     * 获取全部的 <strong>多级分类信息</strong> 列表
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.list')")
    @GetMapping("tree")
    public Object listTree(@PageableDefault(sort = {"sorted"}) Pageable pageable, OrganizationEntity entity) {
        LambdaQueryChainWrapper<OrganizationEntity> lambdaQuery = buildLambdaQuery(entity);
        OrganizationUtils.includes(lambdaQuery, OrganizationEntity::getId);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        List<OrganizationEntity> list = lambdaQuery.list();

        return success(organizationService.converterToTreeDatasource(list));
    }

    /**
     * 以 父级ID 获取全部的 <strong>菜单信息</strong> 列表
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.list')")
    @GetMapping("list-pid-{pid}")
    public Object listPid(@PathVariable(required = false) String pid, @PageableDefault(sort = {"sorted"}) Pageable pageable, OrganizationEntity entity) {
        LambdaQueryChainWrapper<OrganizationEntity> lambdaQuery = buildLambdaQuery(entity);
        OrganizationUtils.includes(lambdaQuery, OrganizationEntity::getId);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        // 搜索条件是否为空
        boolean emptyOfWhere = lambdaQuery.getWrapper().isEmptyOfWhere();
        if (StringUtils.isNotBlank(pid)) {
            lambdaQuery.eq(emptyOfWhere, OrganizationEntity::getPid, pid);
        } else {
            // pid 为 null 或者 空字符串
            lambdaQuery.eq(emptyOfWhere, OrganizationEntity::getPid, "")
                    .or()
                    .isNull(OrganizationEntity::getPid);
        }
        List<OrganizationEntity> list = lambdaQuery.list();

        // 这里处理树形结构数据的时候，不自动加载父级信息，因为会与前端已有的数据冲突
        return success(organizationService.converterToTreeDatasource(list, false));
    }

    /**
     * 获取全部的 <strong>组织机构</strong> 列表
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.list')")
    @GetMapping("all")
    public Object listAll(@PageableDefault Pageable pageable, OrganizationEntity entity) {
        LambdaQueryChainWrapper<OrganizationEntity> lambdaQuery = buildLambdaQuery(entity);
        OrganizationUtils.includes(lambdaQuery, OrganizationEntity::getId);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        return success(lambdaQuery.list());
    }

    /**
     * 分页获取 <strong>组织机构</strong> 列表
     *
     * @param pageable 分页参数信息
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.list')")
    @GetMapping
    public Object list(@PageableDefault Pageable pageable, OrganizationEntity entity) {
        LambdaQueryChainWrapper<OrganizationEntity> lambdaQuery = buildLambdaQuery(entity);
        MyBatisUtils.lambdaQueryAddOrder(lambdaQuery, pageable, entityOrderFields);
        Page<OrganizationEntity> page = lambdaQuery.page(MyBatisUtils.toPage(pageable, false));
        return success(page);
    }

    /**
     * 获取一个 <strong>组织机构</strong>
     *
     * @param id 主键ID
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.info')")
    @GetMapping("{id}")
    public Object info(@PathVariable String id) {
        return success(organizationService.getById(id));
    }

    /**
     * 添加一个 <strong>组织机构</strong>
     *
     * @param entity 修改后的信息
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.add')")
    @PostMapping
    public Object add(@RequestBody OrganizationEntity entity) {
        organizationService.saveOrganization(entity);

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, String.valueOf(entity.getId()));
        return new ResponseEntity<>(headers, HttpStatus.CREATED);
    }

    /**
     * 修改一个 <strong>组织机构</strong>
     *
     * @param id     主键ID
     * @param entity 修改后的信息
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.update')")
    @PutMapping("{id}")
    public Object update(@PathVariable String id, @RequestBody OrganizationEntity entity) {
        entity.setId(id);
        organizationService.updateOrganization(entity);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 删除一个 <strong>组织机构</strong>
     *
     * @param id 主键ID
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.delete')")
    @DeleteMapping("{id}")
    public Object delete(@PathVariable String id) {
        organizationService.deleteOrganization(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    /**
     * 删除多个 <strong>组织机构</strong>
     *
     * @param ids 主键ID列表
     */
    @PreAuthorize("hasAnyRole('ADMIN', 'ORGANIZATION') or hasAnyAuthority('organization.delete')")
    @DeleteMapping
    public Object deleteIds(@RequestBody List<String> ids) {
        organizationService.deleteOrganization(ids);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    /**
     * 获取某个组织机构的角色列表
     *
     * @param orgId 组织机构ID
     */
    @PreAuthorize("hasAnyRole('ADMIN','ORGANIZATION') or hasAnyAuthority('organization.config-roles')")
    @GetMapping("{orgId}/roles")
    public Object getOrganizationRoles(@PathVariable String orgId) {
        return success(roleService.getOrganizationRoles(orgId));
    }

    /**
     * 设置某个组织机构的角色列表（给组织机构分配角色）
     *
     * @param orgId 组织机构ID
     */
    @PreAuthorize("hasAnyRole('ADMIN','ORGANIZATION') or hasAnyAuthority('organization.config-roles')")
    @PutMapping("{orgId}/roles")
    public Object setOrganizationRoles(@PathVariable String orgId, @RequestBody List<RoleEntity> roleEntities) {
        OrganizationEntity entity = new OrganizationEntity();
        entity.setId(orgId);
        entity.setRoles(roleEntities);
        organizationService.setOrganizationRoles(entity);

        return success(null);
    }

    /**
     * 获取某个组织机构的权限列表
     *
     * @param orgId 组织机构ID
     */
    @PreAuthorize("hasAnyRole('ADMIN','ORGANIZATION') or hasAnyAuthority('organization.config-permissions')")
    @GetMapping("{orgId}/permissions")
    public Object getOrganizationPermissions(@PathVariable String orgId) {
        return success(permissionService.getOrganizationPermissions(orgId));
    }

    /**
     * 设置某个组织机构的权限列表（给组织机构分配权限）
     *
     * @param orgId 组织机构ID
     */
    @PreAuthorize("hasAnyRole('ADMIN','ORGANIZATION') or hasAnyAuthority('organization.config-permissions')")
    @PutMapping("{orgId}/permissions")
    public Object setOrganizationPermissions(@PathVariable String orgId, @RequestBody List<PermissionEntity> permissionEntities) {
        OrganizationEntity entity = new OrganizationEntity();
        entity.setId(orgId);
        entity.setPermissions(permissionEntities);
        organizationService.setOrganizationPermissions(entity);

        return success(null);
    }

    /**
     * 构建查询条件内容
     *
     * @param entity 实体对象
     * @return lambda query chain wrapper
     */
    private LambdaQueryChainWrapper<OrganizationEntity> buildLambdaQuery(OrganizationEntity entity) {
        LambdaQueryChainWrapper<OrganizationEntity> lambdaQuery = organizationService.lambdaQuery();
        lambdaQuery.eq(StringUtils.isNotBlank(entity.getId()), OrganizationEntity::getId, entity.getId());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getPid()), OrganizationEntity::getPid, entity.getPid());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getTitle()), OrganizationEntity::getTitle, entity.getTitle());
        lambdaQuery.like(StringUtils.isNotBlank(entity.getRemarks()), OrganizationEntity::getRemarks, entity.getRemarks());
        lambdaQuery.eq(entity.getVersion() != null, OrganizationEntity::getVersion, entity.getVersion());
        lambdaQuery.eq(entity.getGmtCreate() != null, OrganizationEntity::getGmtCreate, entity.getGmtCreate());
        lambdaQuery.eq(entity.getGmtModified() != null, OrganizationEntity::getGmtModified, entity.getGmtModified());
        return lambdaQuery;
    }

}
